package com.itbaizhan.idempotentdemo2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;

//自定义拦截器
@Component
public class MyInceptor implements HandlerInterceptor {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 在方法之前拦截
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
/*当请求被拦截后会进入这里，而HandlerMethod 能获得请求的方法上的参数与注解，通过判断方法上是否有注解
* 从而知道这方法是否开启幂等性处理 */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //HandlerMethod 封装很多属性，在访问请求方法的时候可以方便的访问到访问的参数  或方法上的注解
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        //获得方法
        Method method = handlerMethod.getMethod();
        //判断这个方法有没有添加幂等性注解
        boolean annotationPresent = method.isAnnotationPresent(ApiIdempotentAnn.class);
        //判断是否开启幂等性处理   @ApiIdempotentAnn(value = true)  value也有可能会是false 所以要判断
        if(annotationPresent && method.getAnnotation(ApiIdempotentAnn.class).value()){
            //验证接口幂等性
            boolean result = this.checkToken(request);
            //如果有token,在checkToken()方法就能成功删除token,返回true
            if(result){
                return true; //result是true  就放行
            }else{
                //如果返回是false 说明已经调用过，
                response.setContentType("application/json;charset=utf-8");
                PrintWriter writer = response.getWriter();
                writer.print("重复调用");
                writer.close();
                response.flushBuffer();  //会强行把Buffer的 内容写到客户端浏览器
                return false;
            }

        }

        return false;
    }

    /**
     * 验证token 的有效性
     * @param request
     * @return
     */
    public boolean checkToken(HttpServletRequest request){
        //获取token 从前端页面获取  <input hidden type="text" th:value="${token}" name="token">
        String token = request.getParameter("token");
        //判断 token是null 或者是 空字符串
        if(null ==token || "".equals(token)){
            return false;
        }
        //如果删除成功，证明有token，可以进行页面操作
        return stringRedisTemplate.delete(token);
    }
}
